<!DOCTYPE html>
<html>

  <head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <title>安卓自定义View进阶-MotionEvent详解</title>
  <meta name="description" content="Android MotionEvent 详解，之前用了两篇文章来讲解事件分发，而作为事件分发主角之一的 MotionEvent 并没有过多的说明，本文就带大家了解 MotionEvent 的相关内容，简要介绍触摸事件，主要包括 单点触控、多点触控、鼠标事件 以及 getAction() 和 getActionMa...">
  <meta name="author" content="GcsSloop">
  <meta name="keywords" content="安卓,事件分发,触摸事件,单点触控,多点触控,鼠标事件, getAction()和getActionMasked(),自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  <meta name="关键字" content="安卓,事件分发,触摸事件,单点触控,多点触控,鼠标事件, getAction()和getActionMasked(),自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  

  <meta name="twitter:card" content="summary">
  <meta name="twitter:title" content="安卓自定义View进阶-MotionEvent详解">
  <meta name="twitter:description" content="Android MotionEvent 详解，之前用了两篇文章来讲解事件分发，而作为事件分发主角之一的 MotionEvent 并没有过多的说明，本文就带大家了解 MotionEvent 的相关内容，简要介绍触摸事件，主要包括 单点触控、多点触控、鼠标事件 以及 getAction() 和 getActionMa...">
  <meta name="twitter:keywords" content="安卓,事件分发,触摸事件,单点触控,多点触控,鼠标事件, getAction()和getActionMasked(),自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  
  <meta property="og:type" content="article">
  <meta property="og:title" content="安卓自定义View进阶-MotionEvent详解">
  <meta property="og:description" content="Android MotionEvent 详解，之前用了两篇文章来讲解事件分发，而作为事件分发主角之一的 MotionEvent 并没有过多的说明，本文就带大家了解 MotionEvent 的相关内容，简要介绍触摸事件，主要包括 单点触控、多点触控、鼠标事件 以及 getAction() 和 getActionMa...">
  <meta name="og:keywords" content="安卓,事件分发,触摸事件,单点触控,多点触控,鼠标事件, getAction()和getActionMasked(),自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">

  <meta name="theme-color" content="#343434">
  
  <link rel="icon" type="image/png" href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" />
  <link href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" rel="shortcut icon" type="image/png">
  
  <link href="//netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/css/main.css">

  <link rel="canonical" href="http://www.gcssloop.com/customview/motionevent">
  <link rel="alternate" type="application/rss+xml" title="GcsSloop" href="http://www.gcssloop.com/feed.xml">
  
  <meta name="google-site-verification" content="Z_g58PkzRAyBMxkqrcDdWrTBK8oOWM-7rUHauhLNF2E" />
  <meta name="baidu-site-verification" content="kUtTXCKaZs" />
  <meta name="baidu-site-verification" content="6DuDv3aaJX" />
  
  <!--阅读次数统计-->
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"> </script>
  
  <!--Fuck Weixin and Baidu-->
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv=”Cache-Control” content=”no-siteapp” />
  <meta name="applicable-device" content="pc,mobile">
  <meta name="HandheldFriendly" content="true"/>

  <!-- Google Ad -->
  <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
  <script>
    (adsbygoogle = window.adsbygoogle || []).push({
      google_ad_client: "ca-pub-2767831356529421",
      enable_page_level_ads: true
    });
  </script>

</head>


  <body>

    <span class="mobile btn-mobile-menu">
        <i class="fa fa-list btn-mobile-menu__icon"></i>
        <i class="fa fa-angle-up btn-mobile-close__icon hidden"></i>
    </span>
    
    <header class="panel-cover panel-cover--collapsed" style="background-image: url('/assets/siteinfo/background-cover.jpg')">
  <div class="panel-main">

    <div class="panel-main__inner panel-inverted">
    <div class="panel-main__content">

        <a href="/#blog" title="前往 GcsSloop 的主页" class="blog-button"><img src="/assets/siteinfo/avatar.jpg" width="80" alt="GcsSloop logo" class="panel-cover__logo logo" /></a>
        <h1 class="panel-cover__title panel-title"><a href="/#blog" title="link to homepage for GcsSloop" class="blog-button">GcsSloop</a></h1>

        
        <span class="panel-cover__subtitle panel-subtitle">Just do IT later.</span>
        
        <hr class="panel-cover__divider" />
        <p class="panel-cover__description">嗨，我是 GcsSloop，一名来自2.5次元的魔法师，Android自定义View系列文章作者，非著名程序员。</p>
        <hr class="panel-cover__divider panel-cover__divider--secondary" />
        
        
        <p class="panel-cover__description">欢迎来到我的魔法世界!</p>
        
        
        <div class="navigation-wrapper">
          <div>
            <nav class="cover-navigation cover-navigation--primary">
              <ul class="navigation">
                <li class="navigation__item"><a href="/#blog" title="访问博客" class="blog-button">博客</a></li>
                
                  
                    <li class="navigation__item"><a href="https://github.com/GcsSloop" target="_blank" title="GcsSloop's GitHub">GitHub</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/timeline" title="博客目录">目录</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="https://xiaozhuanlan.com/u/GcsSloop" target="_blank" title="小专栏">专栏</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/category/customview" title="自定义View教程目录">自定义控件</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/friends" title="友链">友链</a></li>
                  
                  
                
              </ul>
            </nav>
          </div>
          
          <div><nav class="cover-navigation navigation--social">
  <ul class="navigation">

  
  <!-- Weibo -->
  <li class="navigation__item">
    <a href="http://weibo.com/GcsSloop" title="@GcsSloop 的微博" target="_blank">
      <i class='social fa fa-weibo'></i>
      <span class="label">Weibo</span>
    </a>
  </li>
  

  
  <!-- Github -->
  <li class="navigation__item">
    <a href="https://github.com/GcsSloop" title="@GcsSloop 的 Github" target="_blank">
      <i class='social fa fa-github'></i>
      <span class="label">Github</span>
    </a>
  </li>
  
  
  
  <!-- Twitter -->
  <li class="navigation__item">
    <a href="http://twitter.com/GcsSloop" title="@GcsSloop" target="_blank">
      <i class='social fa fa-twitter'></i>
      <span class="label">Twitter</span>
    </a>
  </li>
  

    

  

  
  <!-- RSS -->
  <li class="navigation__item">
    <a href="/feed.xml" rel="author" title="RSS" target="_blank">
      <i class='social fa fa-rss'></i>
      <span class="label">RSS</span>
    </a>
  </li>
  

  
  <!-- Email -->
  <li class="navigation__item">
    <a href="mailto:GcsSloop@gmail.com" title="发邮件给我">
      <i class='social fa fa-envelope'></i>
      <span class="label">Email</span>
    </a>
  </li>
  

  
  <!-- Copyright -->
  <li class="navigation__item">
    <a href="http://choosealicense.online" title="选择版权"  target="_blank">
      <i class="social fa fa-copyright"></i>
      <span class="label">版权</span>
    </a>
  </li>
  
  
  </ul>
</nav>
</div>
        </div>
      </div>
    </div>
    
    
    <div class="panel-cover--overlay cover-slate"></div>
    
  </div>
</header>


    <div class="content-wrapper">
        <div class="content-wrapper__inner">
            <article class="post-container post-container--single" itemscope itemtype="http://schema.org/BlogPosting">
  <header class="post-header">
    <div class="post-meta" style="font-size:.8em">
      <time datetime="2016-11-02 00:00:00 +0800" itemprop="datePublished" class="post-meta__date date">2016-11-02</time> &#8226; <span class="post-meta__tags tags">Android,MotionEvent</span> &#8226; View <span id="busuanzi_value_page_pv"></span> times.
</span>
    </div>
    <h1 class="post-title">安卓自定义View进阶-MotionEvent详解</h1>
  </header>

  <section class="post">
    <p>Android MotionEvent 详解，之前用了两篇文章 <a href="http://www.gcssloop.com/customview/dispatch-touchevent-theory" title="安卓自定义View进阶-事件分发机制原理">事件分发机制原理</a> 和 <a href="http://www.gcssloop.com/customview/dispatch-touchevent-source" title="安卓自定义View进阶-事件分发机制详解">事件分发机制详解</a> 来讲解事件分发，而作为事件分发主角之一的 MotionEvent 并没有过多的说明，本文就带大家了解 MotionEvent 的相关内容，简要介绍触摸事件，主要包括 单点触控、多点触控、鼠标事件 以及 getAction() 和 getActionMasked() 的区别。</p>

<p>Android 将所有的输入事件都放在了 MotionEvent 中，随着安卓的不断发展壮大，MotionEvent 也开始变得越来越复杂，下面是我自己整理的 MotionEvent 大事记:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">版本号</th>
      <th>更新内容</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">Android 1.0 (API  1 )</td>
      <td>支持单点触控和轨迹球的事件。</td>
    </tr>
    <tr>
      <td style="text-align: center">Android 1.6 (API  4 )</td>
      <td>支持手势。</td>
    </tr>
    <tr>
      <td style="text-align: center">Android 2.0 (API  5 )</td>
      <td>支持多点触控。</td>
    </tr>
    <tr>
      <td style="text-align: center">Android 3.1 (API 12)</td>
      <td>支持触控笔，鼠标，键盘，操纵杆，游戏控制器等输入工具。</td>
    </tr>
  </tbody>
</table>

<p>以上仅仅是简要的说明几次比较大的变动，细小的修复和更新不计其数，此处就不一一列出了，反正也没人关心这些东西。<br />
MotionEvent 负责集中处理所有类型设备的输入事件，但是由于某些设备使用的几率较小本文会忽略讲解，或者简要讲解，例如：<br />
1、轨迹球只出现在最早的设备上，现代的设备上已经见不到了，本文不再叙述。<br />
2、触控笔和手指处理流程基本相同，不再多说。<br />
3、鼠标在手机上使用概率也比较小，会在文末简要介绍。</p>

<h2 id="单点触控">单点触控</h2>

<p>单点触控就非常简单啦，入门的工程师都会用，上一篇文章也简要介绍过，主要涉及以下几个事件:</p>

<table>
  <thead>
    <tr>
      <th>事件</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ACTION_DOWN</td>
      <td>手指 <strong>初次接触到屏幕</strong> 时触发。</td>
    </tr>
    <tr>
      <td>ACTION_MOVE</td>
      <td>手指 <strong>在屏幕上滑动</strong> 时触发，会多次触发。</td>
    </tr>
    <tr>
      <td>ACTION_UP</td>
      <td>手指 <strong>离开屏幕</strong> 时触发。</td>
    </tr>
    <tr>
      <td>ACTION_CANCEL</td>
      <td>事件 <strong>被上层拦截</strong> 时触发。</td>
    </tr>
    <tr>
      <td>ACTION_OUTSIDE</td>
      <td>手指 <strong>不在控件区域</strong> 时触发。</td>
    </tr>
  </tbody>
</table>

<p>和以下的几个方法:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">方法</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">getAction()</td>
      <td>获取事件类型。</td>
    </tr>
    <tr>
      <td style="text-align: left">getX()</td>
      <td>获得触摸点在当前 View 的 X 轴坐标。</td>
    </tr>
    <tr>
      <td style="text-align: left">getY()</td>
      <td>获得触摸点在当前 View 的 Y 轴坐标。</td>
    </tr>
    <tr>
      <td style="text-align: left">getRawX()</td>
      <td>获得触摸点在整个屏幕的 X 轴坐标。</td>
    </tr>
    <tr>
      <td style="text-align: left">getRawY()</td>
      <td>获得触摸点在整个屏幕的 Y 轴坐标。</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>关于 <code class="highlighter-rouge">get</code> 和 <code class="highlighter-rouge">getRaw</code>  的区别可以参考这一篇文章 <a href="http://www.gcssloop.com/customview/CoordinateSystem" title="安卓自定义View基础-坐标系">安卓自定义View基础-坐标系</a></p>
</blockquote>

<p>单点触控一次简单的交互流程是这样的:</p>

<p><strong>手指落下(ACTION_DOWN) －&gt; 多次移动(ACTION_MOVE) －&gt; 离开(ACTION_UP)</strong></p>

<blockquote>
  <ul>
    <li>本次事例中 ACTION_MOVE 有多次触发。</li>
    <li>如果仅仅是单击(手指按下再抬起)，不会触发 ACTION_MOVE。</li>
  </ul>
</blockquote>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071755.gif?gcssloop" alt="单点触摸事件流程" /></p>

<p>针对单点触控的事件处理一般是这样写的:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
    <span class="c1">// ▼ 注意这里使用的是 getAction()，先埋一个小尾巴。</span>
    <span class="k">switch</span> <span class="o">(</span><span class="n">event</span><span class="o">.</span><span class="na">getAction</span><span class="o">()){</span>
        <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_DOWN</span><span class="o">:</span>
        	<span class="c1">// 手指按下</span>
            <span class="k">break</span><span class="o">;</span>
        <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_MOVE</span><span class="o">:</span>
            <span class="c1">// 手指移动</span>
            <span class="k">break</span><span class="o">;</span>
        <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_UP</span><span class="o">:</span>
            <span class="c1">// 手指抬起</span>
            <span class="k">break</span><span class="o">;</span>
        <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_CANCEL</span><span class="o">:</span>
            <span class="c1">// 事件被拦截 </span>
            <span class="k">break</span><span class="o">;</span>
        <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_OUTSIDE</span><span class="o">:</span>
            <span class="c1">// 超出区域 </span>
            <span class="k">break</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="kd">super</span><span class="o">.</span><span class="na">onTouchEvent</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
<span class="o">}</span>
</code></pre>
</div>

<p>相信小伙伴对此已经非常熟悉了，经常使用的东西，我也不啰嗦了。</p>

<p>但其中有两个比较特殊的事件:  <code class="highlighter-rouge">ACTION_CANCEL</code> 和  <code class="highlighter-rouge">ACTION_OUTSIDE</code> 。<br />
为什么说特殊呢，因为它们是由程序触发而产生的，而且触发条件也非常特殊，通常情况下即便不处理这两个事件也没有什么问题。接下来我们就扒一扒它们的真面目:</p>

<h3 id="action_cancel">ACTION_CANCEL</h3>

<p><strong><code class="highlighter-rouge">ACTION_CANCEL</code> 的触发条件是事件被上层拦截</strong>，然而我们在 <a href="http://www.gcssloop.com/customview/dispatch-touchevent-theory" title="安卓自定义View进阶-事件分发机制原理">事件分发机制原理</a> 一文中了解到当事件被上层 View 拦截的时候，ChildView 是收不到任何事件的，ChildView 收不到任何事件，自然也不会收到 <code class="highlighter-rouge">ACTION_CANCEL</code> 了，所以说这个 <code class="highlighter-rouge">ACTION_CANCEL</code> 的正确触发条件并不是这样，那么是什么呢？</p>

<p><strong>事实上，只有上层 View 回收事件处理权的时候，ChildView 才会收到一个 <code class="highlighter-rouge">ACTION_CANCEL</code> 事件。</strong></p>

<p>这样说可能不太容易理解，咱举个例子?</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071756.jpg?gcssloop" alt="" /></p>

<blockquote>
  <p>例如：上层 View 是一个 RecyclerView，它收到了一个 <code class="highlighter-rouge">ACTION_DOWN</code> 事件，由于这个可能是点击事件，所以它先传递给对应 ItemView，询问 ItemView 是否需要这个事件，然而接下来又传递过来了一个 <code class="highlighter-rouge">ACTION_MOVE</code> 事件，且移动的方向和 RecyclerView 的可滑动方向一致，所以 RecyclerView 判断这个事件是滚动事件，于是要收回事件处理权，这时候对应的 ItemView 会收到一个 <code class="highlighter-rouge">ACTION_CANCEL</code> ，并且不会再收到后续事件。</p>

  <p><strong>通俗一点？</strong></p>

  <p>RecyclerView：儿砸，这里有一个 <code class="highlighter-rouge">ACTION_DOWN</code> 你看你要不要。<br />
ItemView       ：好嘞，我看看。<br />
RecyclerView：噫？居然是移动事件<code class="highlighter-rouge">ACTION_MOVE</code>，我要滚起来了，儿砸，我可能要把你送去你姑父家(缓存区)了，在这之前给你一个 <code class="highlighter-rouge">ACTION_CANCEL</code>，你要收好啊。<br />
ItemView       ：……</p>

  <p>这是实际开发中最有可能见到 <code class="highlighter-rouge">ACTION_CANCEL</code> 的场景了。</p>
</blockquote>

<h3 id="action_outside">ACTION_OUTSIDE</h3>

<p><code class="highlighter-rouge">ACTION_OUTSIDE</code>的触发条件更加奇葩，从字面上看，outside 意思不就是超出区域么？然而不论你如何滑动超出控件区域都不会触发 <code class="highlighter-rouge">ACTION_OUTSIDE</code> 这个事件。相信很多魔法师都对此很是疑惑，说好的超出区域呢？</p>

<p>实际上这个事件根本就不是在这里用的，看官方解释(装一下逼)：</p>

<blockquote>
  <p> A movement has happened outside of the normal bounds of the UI element. This does not provide a full gesture, but only the initial location of the movement/touch.</p>

  <p>一个触摸事件已经发生了UI元素的正常范围之外。因此不再提供完整的手势，只提供 运动/触摸 的初始位置。</p>
</blockquote>

<p>我们知道，正常情况下，如果初始点击位置在该视图区域之外，该视图根本不可能会收到事件，然而，万事万物都不是绝对的，肯定还有一些特殊情况，你可曾还记得点击 Dialog 区域外关闭吗？Dialog 就是一个特殊的视图(没有占满屏幕大小的窗口)，能够接收到视图区域外的事件(虽然在通常情况下你根本用不到这个事件)，除了 Dialog 之外，你最可能看到这个事件的场景是悬浮窗，当然啦，想要接收到视图之外的事件需要一些特殊的设置。</p>

<blockquote>
  <p>设置视图的 WindowManager 布局参数的 flags为<a href="http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_WATCH_OUTSIDE_TOUCH"><code class="highlighter-rouge">FLAG_WATCH_OUTSIDE_TOUCH</code></a>，这样点击事件发生在这个视图之外时，该视图就可以接收到一个 <code class="highlighter-rouge">ACTION_OUTSIDE</code> 事件。</p>

  <p>参见StackOverflow：<a href="http://stackoverflow.com/questions/8384067/how-to-dismiss-the-dialog-with-click-on-outside-of-the-dialog">How to dismiss the dialog with click on outside of the dialog?</a></p>
</blockquote>

<p>由于这个事件用到的几率比较小，此处就不展开叙述了，以后用到的时候再详细讲解。</p>

<h2 id="多点触控">多点触控</h2>

<p>Android 在 2.0 版本的时候开始支持多点触控，一旦出现了多点触控，很多东西就突然之间变得麻烦起来了，首先要解决的问题就是 <strong>多个手指同时按在屏幕上，会产生很多的事件，这些事件该如何区分呢？</strong></p>

<p>为了区分这些事件，工程师们用了一个很简单的办法－－<strong>编号，当手指第一次按下时产生一个唯一的号码，手指抬起或者事件被拦截就回收编号，就这么简单。</strong></p>

<p><strong>第一次按下的手指特殊处理作为主指针，之后按下的手指作为辅助指针</strong>，然后随之衍生出来了以下事件(注意增加的事件和事件简介的变化)：</p>

<table>
  <thead>
    <tr>
      <th>事件</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ACTION_DOWN</td>
      <td><strong>第一个</strong> 手指 <strong>初次接触到屏幕</strong> 时触发。</td>
    </tr>
    <tr>
      <td>ACTION_MOVE</td>
      <td>手指 <strong>在屏幕上滑动</strong> 时触发，会多次触发。</td>
    </tr>
    <tr>
      <td>ACTION_UP</td>
      <td><strong>最后一个</strong> 手指 <strong>离开屏幕</strong> 时触发。</td>
    </tr>
    <tr>
      <td><strong>ACTION_POINTER_DOWN</strong></td>
      <td>有非主要的手指按下(<strong>即按下之前已经有手指在屏幕上</strong>)。</td>
    </tr>
    <tr>
      <td><strong>ACTION_POINTER_UP</strong></td>
      <td>有非主要的手指抬起(<strong>即抬起之后仍然有手指在屏幕上</strong>)。</td>
    </tr>
    <tr>
      <td>以下事件类型不推荐使用</td>
      <td>－－－－－－－－－－－－－－－－－－</td>
    </tr>
    <tr>
      <td><del>ACTION_POINTER_1_DOWN</del></td>
      <td>第 2 个手指按下，已废弃，不推荐使用。</td>
    </tr>
    <tr>
      <td><del>ACTION_POINTER_2_DOWN</del></td>
      <td>第 3 个手指按下，已废弃，不推荐使用。</td>
    </tr>
    <tr>
      <td><del>ACTION_POINTER_3_DOWN</del></td>
      <td>第 4 个手指按下，已废弃，不推荐使用。</td>
    </tr>
    <tr>
      <td><del>ACTION_POINTER_1_UP</del></td>
      <td>第 2 个手指抬起，已废弃，不推荐使用。</td>
    </tr>
    <tr>
      <td><del>ACTION_POINTER_2_UP</del></td>
      <td>第 3 个手指抬起，已废弃，不推荐使用。</td>
    </tr>
    <tr>
      <td><del>ACTION_POINTER_3_UP</del></td>
      <td>第 4 个手指抬起，已废弃，不推荐使用。</td>
    </tr>
  </tbody>
</table>

<p>和以下方法：</p>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>getActionMasked()</td>
      <td>与 <code class="highlighter-rouge">getAction()</code> 类似，<strong>多点触控必须使用这个方法获取事件类型</strong>。</td>
    </tr>
    <tr>
      <td>getActionIndex()</td>
      <td>获取该事件是哪个指针(手指)产生的。</td>
    </tr>
    <tr>
      <td>getPointerCount()</td>
      <td>获取在屏幕上手指的个数。</td>
    </tr>
    <tr>
      <td>getPointerId(int pointerIndex)</td>
      <td>获取一个指针(手指)的唯一标识符ID，在手指按下和抬起之间ID始终不变。</td>
    </tr>
    <tr>
      <td>findPointerIndex(int pointerId)</td>
      <td>通过PointerId获取到当前状态下PointIndex，之后通过PointIndex获取其他内容。</td>
    </tr>
    <tr>
      <td>getX(int pointerIndex)</td>
      <td>获取某一个指针(手指)的X坐标</td>
    </tr>
    <tr>
      <td>getY(int pointerIndex)</td>
      <td>获取某一个指针(手指)的Y坐标</td>
    </tr>
  </tbody>
</table>

<p>由于多点触控部分涉及内容比较多，也很复杂，我准备单独用一篇文章进行详细叙述，所以这里只叙述一些基础的内容作为铺垫：</p>

<h3 id="getaction-与-getactionmasked">getAction() 与 getActionMasked()</h3>

<p>当多个手指在屏幕上按下的时候，会产生大量的事件，如何在获取事件类型的同时区分这些事件就是一个大问题了。</p>

<p>一般来说我们可以通过为事件添加一个int类型的index属性来区分，但是我们知道谷歌工程师是有洁癖的(在 <a href="http://www.gcssloop.com/customview/CustomViewProcess" title="安卓自定义View进阶-分类与流程">自定义View分类与流程</a> 的onMeasure中已经见识过了)，为了添加一个通常数值不会超过10的index属性就浪费一个int大小的空间简直是不能忍受的，于是工程师们将这个index属性和事件类型直接合并了。</p>

<p>int类型共32位(0x00000000)，他们用最低8位(0x000000<strong>ff</strong>)表示事件类型，再往前的8位(0x0000<strong>ff</strong>00)表示事件编号，以手指按下为例讲解数值是如何合成的:</p>

<blockquote>
  <p>ACTION_DOWN                   的默认数值为 (0x00000000)<br />
ACTION_POINTER_DOWN 的默认数值为 (0x00000005)</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th style="text-align: center">手指按下</th>
      <th style="text-align: left">触发事件(数值)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">第1个手指按下</td>
      <td style="text-align: left">ACTION_DOWN                  (0x0000<strong>00</strong>00)</td>
    </tr>
    <tr>
      <td style="text-align: center">第2个手指按下</td>
      <td style="text-align: left">ACTION_POINTER_DOWN (0x0000<strong>01</strong>05)</td>
    </tr>
    <tr>
      <td style="text-align: center">第3个手指按下</td>
      <td style="text-align: left">ACTION_POINTER_DOWN (0x0000<strong>02</strong>05)</td>
    </tr>
    <tr>
      <td style="text-align: center">第4个手指按下</td>
      <td style="text-align: left">ACTION_POINTER_DOWN (0x0000<strong>03</strong>05)</td>
    </tr>
  </tbody>
</table>

<p><strong>注意：</strong><br />
上面表格中用粗体标示出的数值，可以看到随着按下手指数量的增加，这个数值也是一直变化的，进而导致我们使用 <code class="highlighter-rouge">getAction()</code> 获取到的数值无法与标准的事件类型进行对比，为了解决这个问题，他们创建了一个 <code class="highlighter-rouge">getActionMasked()</code> 方法，这个方法可以清除index数值，让其变成一个标准的事件类型。<br />
<strong>1、多点触控时必须使用 <code class="highlighter-rouge">getActionMasked()</code> 来获取事件类型。</strong><br />
<strong>2、单点触控时由于事件数值不变，使用 <code class="highlighter-rouge">getAction()</code> 和 <code class="highlighter-rouge">getActionMasked()</code> 两个方法都可以。</strong><br />
<strong>3、使用 getActionIndex() 可以获取到这个index数值。不过请注意，getActionIndex() 只在 down 和 up 时有效，move 时是无效的。</strong></p>

<p>目前来说获取事件类型使用 <code class="highlighter-rouge">getActionMasked()</code> 就行了，但是如果一定要编译时兼容古董版本的话，可以考虑使用这样的写法:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">final</span> <span class="kt">int</span> <span class="n">action</span> <span class="o">=</span> <span class="o">(</span><span class="n">Build</span><span class="o">.</span><span class="na">VERSION</span><span class="o">.</span><span class="na">SDK_INT</span> <span class="o">&gt;=</span> <span class="n">Build</span><span class="o">.</span><span class="na">VERSION_CODES</span><span class="o">.</span><span class="na">FROYO</span><span class="o">)</span>
                <span class="o">?</span> <span class="n">event</span><span class="o">.</span><span class="na">getActionMasked</span><span class="o">()</span>
                <span class="o">:</span> <span class="n">event</span><span class="o">.</span><span class="na">getAction</span><span class="o">();</span>
<span class="k">switch</span> <span class="o">(</span><span class="n">action</span><span class="o">){</span>
    <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_DOWN</span><span class="o">:</span>
        <span class="c1">// TODO</span>
        <span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
</code></pre>
</div>

<h3 id="pointid">PointId</h3>

<p>虽然前面刚刚说了一个 actionIndex，可以使用 getActionIndex() 获得，但通过 actionIndex 字面意思知道，这个只表示事件的序号，而且根据其说明文档解释，这个 ActionIndex 只有在手指按下(down)和抬起(up)时是有用的，在移动(move)时是没有用的，事件追踪非常重要的一环就是移动(move)，然而它却没卵用，这也太不实在了 (￣Д￣)ﾉ</p>

<p><strong>郑重声明：追踪事件流，请认准 PointId，这是唯一官方指定标准，不要相信 ActionIndex 那个小婊砸。</strong></p>

<p>PointId 在手指按下时产生，手指抬起或者事件被取消后消失，是一个事件流程中唯一不变的标识，可以在手指按下时 通过 <code class="highlighter-rouge">getPointerId(int pointerIndex)</code> 获得。 (参数中的 pointerIndex 就是 actionIndex)</p>

<p>关于事件流的追踪等问题在讲解多点触控时再详细讲解。</p>

<h2 id="历史数据批处理">历史数据(批处理)</h2>

<p>由于我们的设备非常灵敏，手指稍微移动一下就会产生一个移动事件，所以移动事件会产生的特别频繁，为了提高效率，系统会将近期的多个移动事件(move)按照事件发生的顺序进行排序打包放在同一个 MotionEvent 中，与之对应的产生了以下方法：</p>

<table>
  <thead>
    <tr>
      <th>事件</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>getHistorySize()</td>
      <td>获取历史事件集合大小</td>
    </tr>
    <tr>
      <td>getHistoricalX(int pos)</td>
      <td>获取第pos个历史事件x坐标<br /> (pos &lt; getHistorySize())</td>
    </tr>
    <tr>
      <td>getHistoricalY(int pos)</td>
      <td>获取第pos个历史事件y坐标<br /> (pos &lt; getHistorySize())</td>
    </tr>
    <tr>
      <td>getHistoricalX (int pin, int pos)</td>
      <td>获取第pin个手指的第pos个历史事件x坐标<br /> (pin &lt; getPointerCount(), pos &lt; getHistorySize() )</td>
    </tr>
    <tr>
      <td>getHistoricalY (int pin, int pos)</td>
      <td>获取第pin个手指的第pos个历史事件y坐标<br /> (pin &lt; getPointerCount(), pos &lt; getHistorySize() )</td>
    </tr>
  </tbody>
</table>

<p><strong>注意：</strong></p>

<ol>
  <li>pin 全称是 pointerIndex，表示第几个手指，此处为了节省空间使用了缩写。</li>
  <li>历史数据只有 ACTION_MOVE 事件。</li>
  <li>历史数据单点触控和多点触控均可以用。</li>
</ol>

<p>下面是官方文档给出的一个简单使用示例：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">printSamples</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">ev</span><span class="o">)</span> <span class="o">{</span>
     <span class="kd">final</span> <span class="kt">int</span> <span class="n">historySize</span> <span class="o">=</span> <span class="n">ev</span><span class="o">.</span><span class="na">getHistorySize</span><span class="o">();</span>
     <span class="kd">final</span> <span class="kt">int</span> <span class="n">pointerCount</span> <span class="o">=</span> <span class="n">ev</span><span class="o">.</span><span class="na">getPointerCount</span><span class="o">();</span>
     <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">h</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">h</span> <span class="o">&lt;</span> <span class="n">historySize</span><span class="o">;</span> <span class="n">h</span><span class="o">++)</span> <span class="o">{</span>
         <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"At time %d:"</span><span class="o">,</span> <span class="n">ev</span><span class="o">.</span><span class="na">getHistoricalEventTime</span><span class="o">(</span><span class="n">h</span><span class="o">));</span>
         <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="n">pointerCount</span><span class="o">;</span> <span class="n">p</span><span class="o">++)</span> <span class="o">{</span>
             <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"  pointer %d: (%f,%f)"</span><span class="o">,</span>
                 <span class="n">ev</span><span class="o">.</span><span class="na">getPointerId</span><span class="o">(</span><span class="n">p</span><span class="o">),</span> <span class="n">ev</span><span class="o">.</span><span class="na">getHistoricalX</span><span class="o">(</span><span class="n">p</span><span class="o">,</span> <span class="n">h</span><span class="o">),</span> <span class="n">ev</span><span class="o">.</span><span class="na">getHistoricalY</span><span class="o">(</span><span class="n">p</span><span class="o">,</span> <span class="n">h</span><span class="o">));</span>
         <span class="o">}</span>
     <span class="o">}</span>
     <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"At time %d:"</span><span class="o">,</span> <span class="n">ev</span><span class="o">.</span><span class="na">getEventTime</span><span class="o">());</span>
     <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="n">pointerCount</span><span class="o">;</span> <span class="n">p</span><span class="o">++)</span> <span class="o">{</span>
         <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"  pointer %d: (%f,%f)"</span><span class="o">,</span>
             <span class="n">ev</span><span class="o">.</span><span class="na">getPointerId</span><span class="o">(</span><span class="n">p</span><span class="o">),</span> <span class="n">ev</span><span class="o">.</span><span class="na">getX</span><span class="o">(</span><span class="n">p</span><span class="o">),</span> <span class="n">ev</span><span class="o">.</span><span class="na">getY</span><span class="o">(</span><span class="n">p</span><span class="o">));</span>
     <span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>

<h2 id="获取事件发生的时间">获取事件发生的时间</h2>

<p>获取事件发生的时间。</p>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>getDownTime()</td>
      <td>获取手指按下时的时间。</td>
    </tr>
    <tr>
      <td>getEventTime()</td>
      <td>获取当前事件发生的时间。</td>
    </tr>
    <tr>
      <td>getHistoricalEventTime(int pos)</td>
      <td>获取历史事件发生的时间。</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <ol>
    <li>pos 表示历史数据中的第几个数据。( pos &lt; getHistorySize() )</li>
    <li>返回值类型为 long，单位是毫秒。</li>
  </ol>
</blockquote>

<h2 id="获取压力接触面积大小">获取压力(接触面积大小)</h2>

<p>MotionEvent支持获取某些输入设备(手指或触控笔)的与屏幕的接触面积和压力大小，主要有以下方法：</p>

<blockquote>
  <p>描述中使用了手指，触控笔也是一样的。</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>getSize ()</td>
      <td>获取第1个手指与屏幕接触面积的大小</td>
    </tr>
    <tr>
      <td>getSize (int pin)</td>
      <td>获取第pin个手指与屏幕接触面积的大小</td>
    </tr>
    <tr>
      <td>getHistoricalSize (int pos)</td>
      <td>获取历史数据中第1个手指在第pos次事件中的接触面积</td>
    </tr>
    <tr>
      <td>getHistoricalSize (int pin, int pos)</td>
      <td>获取历史数据中第pin个手指在第pos次事件中的接触面积</td>
    </tr>
    <tr>
      <td>getPressure ()</td>
      <td>获取第一个手指的压力大小</td>
    </tr>
    <tr>
      <td>getPressure (int pin)</td>
      <td>获取第pin个手指的压力大小</td>
    </tr>
    <tr>
      <td>getHistoricalPressure (int pos)</td>
      <td>获取历史数据中第1个手指在第pos次事件中的压力大小</td>
    </tr>
    <tr>
      <td>getHistoricalPressure (int pin, int pos)</td>
      <td>获取历史数据中第pin个手指在第pos次事件中的压力大小</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <ol>
    <li>pin 全称是 pointerIndex，表示第几个手指。(pin &lt; getPointerCount() )</li>
    <li>pos 表示历史数据中的第几个数据。( pos &lt; getHistorySize() )</li>
  </ol>
</blockquote>

<p><strong>注意：</strong></p>

<p><strong>1、获取接触面积大小和获取压力大小是需要硬件支持的。</strong><br />
<strong>2、非常不幸的是大部分设备所使用的电容屏不支持压力检测，但能够大致检测出接触面积。</strong><br />
<strong>3、大部分设备的 <code class="highlighter-rouge">getPressure()</code> 是使用接触面积来模拟的。</strong><br />
<strong>4、由于某些未知的原因(可能系统版本和硬件问题)，某些设备不支持该方法。</strong></p>

<p>我用不同的设备对这两个方法进行了测试，然而不同设备测试出来的结果不相同，之后经过我多方查证，发现是系统问题，有的设备上只有 <code class="highlighter-rouge">getSize()</code> 能用，有的设备上只有 <code class="highlighter-rouge">getPressure()</code> 能用，而有的则两个都不能用。</p>

<p><strong>由于获取接触面积和获取压力大小受系统和硬件影响，使用的时候一定要进行数据检测，以防因为设备问题而导致程序出错。</strong></p>

<h2 id="鼠标事件">鼠标事件</h2>

<p>由于触控笔事件和手指事件处理流程大致相同，所以就不讲解了，这里讲解一下与鼠标相关的几个事件：</p>

<table>
  <thead>
    <tr>
      <th>事件</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ACTION_HOVER_ENTER</td>
      <td>指针移入到窗口或者View区域，但没有按下。</td>
    </tr>
    <tr>
      <td>ACTION_HOVER_MOVE</td>
      <td>指针在窗口或者View区域移动，但没有按下。</td>
    </tr>
    <tr>
      <td>ACTION_HOVER_EXIT</td>
      <td>指针移出到窗口或者View区域，但没有按下。</td>
    </tr>
    <tr>
      <td>ACTION_SCROLL</td>
      <td>滚轮滚动，可以触发水平滚动(AXIS_HSCROLL)或者垂直滚动(AXIS_VSCROLL)</td>
    </tr>
  </tbody>
</table>

<p>注意：</p>

<p>1、这些事件类型是 安卓4.0 (API 14) 才添加的。<br />
2、使用 ` getActionMasked()` 获得这些事件类型。<br />
3、这些事件不会传递到 <a href="https://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent)">onTouchEvent(MotionEvent)</a> 而是传递到 <a href="https://developer.android.com/reference/android/view/View.html#onGenericMotionEvent(android.view.MotionEvent)">onGenericMotionEvent(MotionEvent)</a> 。</p>

<h2 id="输入设备类型判断">输入设备类型判断</h2>

<p>输入设备类型判断也是安卓4.0 (API 14) 才添加的，主要包括以下几种设备：</p>

<table>
  <thead>
    <tr>
      <th>设备类型</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>TOOL_TYPE_ERASER</td>
      <td>橡皮擦</td>
    </tr>
    <tr>
      <td>TOOL_TYPE_FINGER</td>
      <td>手指</td>
    </tr>
    <tr>
      <td>TOOL_TYPE_MOUSE</td>
      <td>鼠标</td>
    </tr>
    <tr>
      <td>TOOL_TYPE_STYLUS</td>
      <td>手写笔</td>
    </tr>
    <tr>
      <td>TOOL_TYPE_UNKNOWN</td>
      <td>未知类型</td>
    </tr>
  </tbody>
</table>

<p><strong>使用 <code class="highlighter-rouge">getToolType(int pointerIndex)</code> 来获取对应的输入设备类型，pointIndex可以为0，但必须小于 <code class="highlighter-rouge">getPointerCount()</code>。</strong></p>

<h2 id="总结">总结</h2>

<p>虽然本文标题是 MotionEvent 详解，但由于 MotionEvent 实在太庞大了，本文只能涉及一些比较常用的内容，某些不太常用的内容就在以后用到的时候再详细介绍吧，像游戏手柄等输入设备由于我暂时不做游戏开发，也没有过多了解，所以就不介绍给大家啦。</p>

<p>由于个人水平有限，文章中可能会出现错误，如果你觉得哪一部分有错误，或者发现了错别字等内容，欢迎在评论区告诉我，另外，据说关注 <a href="http://weibo.com/GcsSloop">作者微博</a> 不仅能第一时间收到新文章消息，还能变帅哦。</p>

<h2 id="参考资料">参考资料</h2>

<p><a href="https://developer.android.com/reference/android/view/MotionEvent.html">MotionEvent </a><br />
<a href="http://www.jianshu.com/p/0c863bbde8eb">Android MotionEvent详解</a></p>

<h2 id="about-me">About Me</h2>

<h3 id="作者微博-gcssloop">作者微博: <a href="http://weibo.com/GcsSloop" target="_blank">@GcsSloop</a></h3>

<p><a href="http://www.gcssloop.com/info/about" target="_blank"><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/gcs_banner.jpg?gcssloop" width="300" style="display:inline;" /></a></p>


    <hr>
  </section>
</article>

<!--广告-->

<!--
<div>
<a href="https://m.aliyun.com/act/team1111/?spm=5176.11533457.1089570.5.424777e3AF8WOJ&userCode=hn5smxtw#/" target="_blank"><img src="/assets/aliyun/1111-980-120.jpg" width="100%"></a>
</div>
-->
<!--捐赠晶石-->
<section class="contribute">
    <script type="text/javascript"> 
      function toggle() {
        var con = document.getElementById("contribute");
        if (con.style.display == "none") {
          con.style.display = "block";
        } else {
          con.style.display = "none";
        }
      }
    </script> 
    <blockquote style="background-color:#F5F5F5; padding: 10px 20px 20px 10px; margin:0px" >
      <h4> 如果你觉得我的文章对你有帮助的话，欢迎赞助一些服务器费用! </h4>
      <p></p>
      <a id=“btn-toggle-contribute” class="btn-contribute" onclick="toggle()" >¥ 点击赞助</a>
      <br>
      <div id="contribute" style="display:none;">
        <p align="center" >
        <img src="/assets/images/wechat.png" alt="微信">
        <img src="/assets/images/alipay.png" alt="支付宝">
        </p>
        <p align="left" >
          <b>感谢所有支持我的魔法师，所有支持过我的魔法师都可以通过微信(GcsSloop)联系我，获赠我的付费专栏！</b>
          <!--
          <a href="/contribute">点击这里查看捐赠者名单。</a>
          -->
        </p>
      </div>
    </blockquote>
</section>
<div>
  <h2>欢迎关注我的微信公众号</h2>
  <img src="/assets/images/banner.jpg" width="100%">
</div>

<!--阅读更多-->
<section class="read-more">
  
  
  <div class="read-more-item">
    <span class="read-more-item-dim">最近的文章</span>
    <h2 class="post-list__post-title post-title"><a href="/markdown/markdown-links" title="link to Markdown实用技巧－链接和图片">Markdown实用技巧－链接和图片</a></h2>
    <p class="excerpt">Sloop 喝过半杯咖啡，涨红的脸色渐渐复了原，旁人便又问道，“ Sloop，你当真会写文章么？” Sloop 看着问他的人，显出不屑置辩的神气。他们便接着说道，“你怎的连半个赞也捞不到呢？” ...&hellip;</p>
    <div class="post-list__meta">
      <time datetime="2016-11-08 00:00:00 +0800" class="post-list__meta--date date">2016-11-08</time> &#8226; <span class="post-list__meta--tags tags">Markdown</span>
      <br/><br/>
      <a style="float:none; margin:0 auto;" class="btn-border-small" href=/markdown/markdown-links>继续阅读</a></div>
   </div>
   
   
   
   
   <div class="read-more-item">
       <span class="read-more-item-dim">更早的文章</span>
       <h2 class="post-list__post-title post-title"><a href="/markdown/markdown-grammar" title="link to Markdown实用技巧－基础语法">Markdown实用技巧－基础语法</a></h2>
       <p class="excerpt">本文为 Markdown实用技巧 系列的基础文章，并没有不可描述的内容 (⊙ω⊙)为保证语法兼容性，本文只介绍基础语法，扩展语法等其它内容，会在后续的文章中单独介绍。注意：所有的标记符号均使用英...&hellip;</p>
       <div class="post-list__meta">
          <time datetime="2016-10-25 00:00:00 +0800" class="post-list__meta--date date">2016-10-25</time> &#8226; <span class="post-list__meta--tags tags">Markdown</span>
          <br/><br/>
          <a style="float:none; margin:0 auto;" class="btn-border-small" href=/markdown/markdown-grammar>继续阅读</a>
       </div>
   </div>
   
</section>

<!--网易云跟帖-->
<!--
<div id="cloud-tie-wrapper" class="cloud-tie-wrapper"></div>
<script src="https://img1.cache.netease.com/f2e/tie/yun/sdk/loader.js"></script>
<script>
var cloudTieConfig = {
  url: document.location.href, 
  sourceId: "",
  productKey: "a85dba2840134721a7b69a15b2e0f217",
  target: "cloud-tie-wrapper"
};
var yunManualLoad = true;
Tie.loader("aHR0cHM6Ly9hcGkuZ2VudGllLjE2My5jb20vcGMvbGl2ZXNjcmlwdC5odG1s", true);
</script>
-->

<style type="text/css">
.isso-comment > div.avatar {
    border: 0px;
    box-shadow: none;
    display: block;
    float: left;
    width: 7%;
    margin: 3px 15px 0 0;
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input {
    border-radius: 6px;
    padding: 6px;
    padding-left: 16px;
    padding-right: 16px;
    border: 1px solid #CCC;
    background-color: #D58D44;
    cursor: pointer;
    outline: 0;
    color: #fff;
    size: 10;
    line-height: 1.4em;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input:hover {
    background-color: #272822;
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input:active {
    background-color: #986530;
}
</style>

<section id="isso-thread"></section>

<script data-isso="//47.52.58.34:1234/"
        data-isso-css="true"
        data-isso-lang="zh"
        data-isso-reply-to-self="false"
        data-isso-require-author="false"
        data-isso-require-email="false"
        data-isso-max-comments-top="10"
        data-isso-max-comments-nested="5"
        data-isso-reveal-on-click="5"
        data-isso-avatar="true"
        data-isso-avatar-bg="#f0f0f0"
        data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
        data-isso-vote="true"
        data-vote-levels=""
        src="//47.52.58.34:1234/js/embed.min.js">
        </script>

<!--
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
-->
<!-- OneV's Den -->
<!--
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-3324997515191619"
     data-ad-slot="9170309685"
     data-ad-format="auto"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
-->

            <section class="footer">
    <footer>
    	<span class="footer__copyright">本站点采用<a rel="license" href="https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh" target="_blank">知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议</a></span>
        <span class="footer__copyright">本站由 <a href="http://www.GcsSloop.com">@GcsSloop</a> 创建，采用 <a href="https://github.com/GcsSloop/Gcs-Vno-Jekyll" target="_blank">Gcs-Vno-Jekyll</a> 作为主题。<span id="busuanzi_container_site_pv"> 总访问量 <span id="busuanzi_value_site_pv"></span> 次</span> - &copy; 2019</span>
        <span class="footer__sitemap, footer__copyright"><a href="http://www.gcssloop.com/sitemap.xml" target="_blank">Site Map</a>
        <a href="http://www.gcssloop.com/vip" target="_blank">vip</a></span>
    </footer>
</section>

        </div>
    </div>
    
    <script type="text/javascript" src="//code.jquery.com/jquery-1.11.3.min.js"></script>

<script type="text/javascript" src="/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<script type="text/javascript" src="/js/main.js"></script>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-82493667-1', 'auto');
  ga('send', 'pageview');

</script>

    
  </body>

</html>
